﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//------
using Ecng.Collections;
using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;

using StockSharp.Algo;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Xaml;
using StockSharp.Algo.Indicators.Williams;
//------


namespace Atentis_Connector
{
	/// <summary>
	/// Тестовая стратегия на скользяшках
	/// </summary>
	class WilliamsStrategy : IStrategy
	{

		private double m_LastSellPrice;
		private double m_LastBuyPrice;

		private string m_SecCode;
		/// <summary>
		/// Кодовое название бумаги
		/// </summary>
		public string SecCode { get { return m_SecCode; } set { m_SecCode = value; } }

		private StrategySettings m_StrategySettings;
		public StrategySettings StrategySettings { get { return m_StrategySettings; } set { m_StrategySettings = value; } }

		private string m_StategyName;
		/// <summary>
		/// Название стратегии
		/// </summary>
		public string StategyName { get { return m_StategyName; } set { m_StategyName = value; } }

		private List<Candle> m_Candles;
		private StockViewer m_StockViewer;

		/// <summary>
		/// Событие - форма с графиком закрыта
		/// </summary>
		public event EventHandler CloseStrategy;
		void OnCloseStrategy(EventArgs e)
		{
			EventHandler closeStrategy = CloseStrategy;
			if (closeStrategy != null)
				closeStrategy(this, e);
		}

		private SimpleMovingAverage m_Sma;
		private Dictionary<int, decimal> m_SmaValues;

		private Dictionary<int, decimal> m_RisingFracValues;
		private Dictionary<int, decimal> m_FallingFracValues;

		private Fractals m_Fractals;
		private Dictionary<int, decimal> m_FractalsValues;

		private Alligator m_Alligator;
		private Dictionary<int, decimal> m_JewsValues;
		private Dictionary<int, decimal> m_TeethValues;
		private Dictionary<int, decimal> m_LipsValues;

		private AwesomeOscillator m_AO;
		private Dictionary<int, decimal> m_AOValues;

		public double Price { get { return m_Candles.Last().Close; } }

		const int SMAPERIOD = 7;

		private bool MayInSellPosition;
		private bool MayInBuyPosition;

		private bool IsUpSaucer;
		private bool IsDownSaucer;

		private bool IsUpCross;
		private bool IsDownCross;

		public WilliamsStrategy()
		{
			m_Sma = new SimpleMovingAverage();
			m_Sma.Length = SMAPERIOD;
			m_Candles = new List<Candle>();
			m_SmaValues = new Dictionary<int, decimal>();
			m_StockViewer = new StockViewer();
			m_StockViewer.CloseForm += m_StockViewer_CloseForm;
			//Для отображения SMA
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для отображения фракталда вверх
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для отображения фрактала вниз
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());

			//Для отображения челюстей
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для отображения губ
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для отображения зубов
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для отображения AO
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());

			//Для отображения фракталов вверх
			m_RisingFracValues = new Dictionary<int, decimal>();
			//Для отображения фракталов вниз
			m_FallingFracValues = new Dictionary<int, decimal>();

			m_Fractals = new Fractals();
			m_Fractals.Length = 5;
			m_FractalsValues = new Dictionary<int, decimal>();

			m_JewsValues = new Dictionary<int, decimal>();
			m_TeethValues = new Dictionary<int, decimal>();
			m_LipsValues = new Dictionary<int, decimal>();

			m_Alligator = new Alligator();

			m_AO = new AwesomeOscillator();
			m_AOValues = new Dictionary<int, decimal>();

			IsUpSaucer = false;
			IsDownSaucer = false;

			IsUpCross = false;
			IsDownCross = false;

			CropLastValues(60);

			StrategySettings = new StrategySettings(15, 20, 50, false, false);

			m_LastSellPrice = 0;
			m_LastBuyPrice = 0;

			MayInSellPosition = false;
			MayInBuyPosition = false;
		}

		private void CropLastValues(int n)
		{
			// Отрезаем последние n значений, чтобы не грузить комп
			m_StockViewer.DrawLast = n;
		}

		void m_StockViewer_CloseForm(object sender, EventArgs e)
		{
			OnCloseStrategy(new EventArgs());
		}
		
		public event EventHandler NeedSell;
		void OnNeedSell(EventArgs e)
		{
			EventHandler needSell = NeedSell;
			if (needSell != null)
				needSell(this, e);
		}
		public event EventHandler NeedBuy;
		void OnNeedBuy(EventArgs e)
		{
			EventHandler needBuy = NeedBuy;
			if (needBuy != null)
				needBuy(this, e);
		}

		public event EventHandler CloseSell;
		void OnCloseSell(EventArgs e)
		{
			EventHandler closeSell = CloseSell;
			if (closeSell != null)
				closeSell(this, e);
		}
		public event EventHandler CloseBuy;
		void OnCloseBuy(EventArgs e)
		{
			EventHandler closeBuy = CloseBuy;
			if (closeBuy != null)
				closeBuy(this, e);
		}
		/// <summary>
		/// Установить историю
		/// </summary>
		/// <param name="candles">Список свечей</param>
		public void SetHistory(List<Candle> candles)
		{
			m_Candles.Clear();
			for (int i = 0; i < candles.Count - 1; i++)
			{
				NewCandle(candles[i]);
			}
		}

		/// <summary>
		/// Добавить свечу
		/// </summary>
		/// <param name="candle">Свеча</param>
		public void NewCandle(Candle candle)
		{
			m_Candles.Add(candle);
			PorcessCandle(candle);
			m_StockViewer.AddCandle(m_Candles);
		}

		#region Обработка по алгоритму
		/// <summary>
		/// Обработка свечи по алгоритму
		/// </summary>
		/// <param name="candle">Свеча</param>
		private void PorcessCandle(Candle candle)
		{

			var c = StockShaprTransport.GetStockSharpCandle(candle);

			var lastSmaValue = m_Sma.Process((DecimalIndicatorValue)c.ClosePrice);
			if (m_Sma.IsFormed)
				m_SmaValues.Add(m_SmaValues.Count + 1, lastSmaValue.GetValue<decimal>());
			else
				m_SmaValues.Add(m_SmaValues.Count + 1, c.ClosePrice);

			var lastAligatorJawsValue = m_Alligator.Jaw.Process((CandleIndicatorValue)c);
			var lastAligatorTeethValue = m_Alligator.Teeth.Process((CandleIndicatorValue)c);
			var lastAligatorLipsValue = m_Alligator.Lips.Process((CandleIndicatorValue)c);
			if (m_Alligator.IsFormed)
			{
				m_JewsValues.Add(m_SmaValues.Count + 1, lastAligatorJawsValue.GetValue<decimal>());
				m_TeethValues.Add(m_SmaValues.Count + 1, lastAligatorTeethValue.GetValue<decimal>());
				m_LipsValues.Add(m_SmaValues.Count + 1, lastAligatorLipsValue.GetValue<decimal>());
			}
			else
			{
				m_JewsValues.Add(m_SmaValues.Count + 1, c.ClosePrice);
				m_TeethValues.Add(m_SmaValues.Count + 1, c.ClosePrice);
				m_LipsValues.Add(m_SmaValues.Count + 1, c.ClosePrice);
			}
			var lastFractalsValue = m_Fractals.Process((CandleIndicatorValue)c);
			if (m_Fractals.IsFormed)
			{
				m_Fractals.Name = "test";
				var u = m_Fractals.Up;
				var d = m_Fractals.Down;
				var q = m_Fractals.Up.LastValue;
				var w = m_Fractals.Down.LastValue;
				if (q.Value != null && !q.Value.IsEmpty) { m_RisingFracValues.Clear(); m_RisingFracValues.Add(m_SmaValues.Count + 1, q.Value.GetValue<decimal>()); }
				if (w.Value != null && !w.Value.IsEmpty) { m_FallingFracValues.Clear(); m_FallingFracValues.Add(m_SmaValues.Count + 1, w.Value.GetValue<decimal>()); }
			}

			var lastAOValue = m_AO.Process((CandleIndicatorValue)c);
			if (m_AO.IsFormed)
			{
				m_AOValues.Add(m_SmaValues.Count + 1, lastAOValue.GetValue<decimal>());
				if (m_AOValues.Count > 40)
				{
					if (m_AOValues[m_AOValues.Count - 3] > 0 && m_AOValues[m_AOValues.Count - 2] > 0 && m_AOValues[m_AOValues.Count - 3] > 0 && m_AOValues[m_AOValues.Count - 3] > m_AOValues[m_AOValues.Count - 2] && m_AOValues[m_AOValues.Count - 2] < m_AOValues[m_AOValues.Count - 1])
						IsUpSaucer = true;
					else
						IsUpSaucer = false;

					if (m_AOValues[m_AOValues.Count - 3] < 0 && m_AOValues[m_AOValues.Count - 2] < 0 && m_AOValues[m_AOValues.Count - 1] < 0 && m_AOValues[m_AOValues.Count - 3] < m_AOValues[m_AOValues.Count - 2] && m_AOValues[m_AOValues.Count - 2] > m_AOValues[m_AOValues.Count - 1])
						IsDownSaucer = true;
					else
						IsDownSaucer = false;

					if (m_AOValues[m_AOValues.Count - 2] < 0 && m_AOValues[m_AOValues.Count - 1] > 0 && m_AOValues[m_AOValues.Count - 2] < m_AOValues[m_AOValues.Count - 1])
						IsUpCross = true;
					else
						IsUpCross = false;

					if (m_AOValues[m_AOValues.Count - 2] > 0 && m_AOValues[m_AOValues.Count - 1] < 0 && m_AOValues[m_AOValues.Count - 2] > m_AOValues[m_AOValues.Count - 1])
						IsDownCross = true;
					else
						IsDownCross = false;

				}
			}
			else
			{
				m_AOValues.Add(m_SmaValues.Count + 1, 0);
			}

			if (m_Alligator.IsFormed && m_Fractals.IsFormed)
			{
				// Проверяем условия по стратегии Вильямса. Если выполнены - кидаем заявку.
				if (!m_StrategySettings.UseFraqPosition && !MayInBuyPosition && !MayInSellPosition)
				{
					if (c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value)
					{
						MayInBuyPosition = true;
						OnNeedBuy(new EventArgs());
					}
					if (c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value)
					{
						MayInSellPosition = true;
						OnNeedSell(new EventArgs());
					}
				}
				if (m_StrategySettings.UseFraqPosition && !MayInBuyPosition && !MayInSellPosition)
				{
					if (c.ClosePrice > m_TeethValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value && c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value)
					{
						MayInBuyPosition = true;
						OnNeedBuy(new EventArgs());
					}
					if (c.ClosePrice < m_TeethValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value && c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value)
					{
						MayInSellPosition = true;
						OnNeedSell(new EventArgs());
					}
				}
				/*
				if (!m_StrategySettings.UseAO && !m_StrategySettings.UseFraqPosition)
				{
					if (c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value)
						OnNeedBuy(new EventArgs());
					if (c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value)
						OnNeedSell(new EventArgs());
				}
				if (m_StrategySettings.UseAO && !m_StrategySettings.UseFraqPosition)
				{
					if (c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value && (IsUpSaucer || IsUpCross))
						OnNeedBuy(new EventArgs());
					if (c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value && (IsDownSaucer || IsDownCross))
						OnNeedSell(new EventArgs());
				}
				if (!m_StrategySettings.UseAO && m_StrategySettings.UseFraqPosition)
				{
					if (c.ClosePrice > m_TeethValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value && c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value)
						OnNeedBuy(new EventArgs());
					if (c.ClosePrice < m_TeethValues.Last().Value && m_RisingFracValues.Last().Value < m_TeethValues.Last().Value && c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value)
						OnNeedSell(new EventArgs());
				}
				if (m_StrategySettings.UseAO && m_StrategySettings.UseFraqPosition)
				{
					if (c.ClosePrice > m_TeethValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value && c.ClosePrice > m_RisingFracValues.Last().Value + this.StrategySettings.Threshold && m_LipsValues.Last().Value > m_TeethValues.Last().Value && m_TeethValues.Last().Value > m_JewsValues.Last().Value && m_RisingFracValues.Last().Value > m_TeethValues.Last().Value && (IsUpSaucer || IsUpCross))
						OnNeedBuy(new EventArgs());
					if (c.ClosePrice < m_TeethValues.Last().Value && m_RisingFracValues.Last().Value < m_TeethValues.Last().Value && c.ClosePrice < m_FallingFracValues.Last().Value - this.StrategySettings.Threshold && m_LipsValues.Last().Value < m_TeethValues.Last().Value && m_TeethValues.Last().Value < m_JewsValues.Last().Value && m_FallingFracValues.Last().Value < m_TeethValues.Last().Value && (IsDownSaucer || IsDownCross))
						OnNeedSell(new EventArgs());
				}
				*/
				// Закрываем позу по пересечению зеленой линии
				if (c.ClosePrice > m_LipsValues.Last().Value && MayInSellPosition)
				{
					MayInSellPosition = false;
					OnCloseSell(new EventArgs());
				}
				if (c.ClosePrice < m_LipsValues.Last().Value && MayInBuyPosition)
				{
					MayInBuyPosition = false;
					OnCloseBuy(new EventArgs());
				}
				// Закрываем позу по пересечению StopLoss
				if (c.ClosePrice >= (decimal)m_LastSellPrice + this.StrategySettings.StopLoss && MayInSellPosition)
				{
					MayInSellPosition = false;
					OnCloseSell(new EventArgs());
				}

				if (c.ClosePrice <= (decimal)m_LastBuyPrice - this.StrategySettings.StopLoss && MayInBuyPosition)
				{
					MayInBuyPosition = false;
					OnCloseBuy(new EventArgs());
				}

				///Добавляемся, если есть сигналы от AO
				if (m_StrategySettings.UseAO)
				{
					if (MayInBuyPosition && (IsUpSaucer || IsUpCross) && MayInBuyPosition) OnNeedBuy(new EventArgs());
					if (MayInSellPosition && (IsDownSaucer || IsDownCross) && MayInSellPosition) OnNeedSell(new EventArgs());
				}

			}

			//m_StockViewer.Indicators[0] = m_SmaValues;
			m_StockViewer.Indicators[1] = m_RisingFracValues;
			m_StockViewer.Indicators[2] = m_FallingFracValues;
			m_StockViewer.Indicators[3] = m_JewsValues;
			m_StockViewer.Indicators[4] = m_TeethValues;
			m_StockViewer.Indicators[5] = m_LipsValues;
			m_StockViewer.Indicators[6] = m_AOValues;
		}

		#endregion Обработка по алгоритму

		/// <summary>
		/// Дабавить сделку
		/// </summary>
		/// <param name="trade">Сделка</param>
		public void NewTrade(WrapperTrades trade)
		{
			if (m_Candles.Count() > 0)
			{
				m_Candles.Last().Close = trade.Price;
				PorcessCandle(m_Candles.Last());
				m_StockViewer.EditCandle(m_Candles);
			}
		}

		/// <summary>
		/// Закрыть окно данной стратегии.
		/// </summary>
		public void RemoveThatStrategy()
		{
			m_StockViewer.CloseThatForm();
		}

	}
}
